home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / ptv3n5.zip / FPNUM.CPP < prev    next >
C/C++ Source or Header  |  1992-09-20  |  7KB  |  234 lines

  1. /*==================================================================
  2.  fpmath.cpp -- Fixed point math class [Listing #2]
  3.  by Robert N. Goldrich
  4.  Tested with Borland, Microsoft, Zortech, and TopSpeed C++
  5. ==================================================================*/
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <ctype.h>
  9. #include <iostream.h>
  10.  
  11. #include "fpnum.h"
  12.  
  13. /*------------------------------------------------------------------
  14.  fixed point multiply
  15. ------------------------------------------------------------------*/
  16. fpnum operator*( const fpnum& a, const fpnum& b )
  17. {
  18.     long a_int  = a.xx >> FP_FRCBITS ;
  19.     long b_int  = b.xx >> FP_FRCBITS ;
  20.     long a_frac = a.xx - ( a_int << FP_FRCBITS ) ;
  21.     long b_frac = b.xx - ( b_int << FP_FRCBITS ) ;
  22.  
  23.     long term1 = a_int * b_int ;
  24.     long term2 = ( b_frac >> 1 ) * ( a_frac >> 1 ) ;
  25.                    // use >> 1 to avoid overflow
  26.     long term3 = ( a_int * b_frac + b_int * a_frac ) ;
  27.  
  28.     long ans = (term1<<FP_FRCBITS)+ (term2>>(FP_FRCBITS-2))+ term3;
  29.     return fpnum( ans ) ;                   // private constructor
  30. }
  31.  
  32.  
  33. /*------------------------------------------------------------------
  34.  fixed point divide
  35. ------------------------------------------------------------------*/
  36. fpnum  operator/( const fpnum& a, const fpnum& b )
  37. {
  38.     long whole = (a.xx / b.xx) << FP_FRCBITS ;
  39.     long fract = a.xx % b.xx ;
  40.     long abs2  = fract < 0 ? -fract : fract ;   //  | remainder |
  41.     long mask  = 1L << (FP_TOTBITS-2) ;
  42.  
  43.     // look for 1st non-zero bit, but not beyond FP_FRCBITS
  44.     int shift = 0 ;
  45.     while( !(mask & abs2 ) && shift < FP_FRCBITS ) {
  46.         shift++ ;
  47.         mask >>= 1 ;
  48.     }
  49.  
  50.     fract = ( fract << shift ) / ( b.xx >> (FP_FRCBITS-shift) ) ;
  51.     return fpnum( whole + fract ) ;         // private constructor
  52. }
  53.  
  54.  
  55. /*------------------------------------------------------------------
  56.  Round to nearest integer -- return an integer.
  57. ------------------------------------------------------------------*/
  58. int round_to_int( const fpnum& a )
  59. {
  60.     if( a.xx < 0 ) {
  61.         return  -( (-a.xx+FP_HALF) >> FP_FRCBITS ) ;
  62.     }
  63.     else {
  64.         return  ( a.xx+FP_HALF ) >> FP_FRCBITS ;
  65.     }
  66. }
  67.  
  68. /*------------------------------------------------------------------
  69.  Truncates fraction and returns an integer.
  70. ------------------------------------------------------------------*/
  71. int trunc_to_int( const fpnum& a )
  72. {
  73.     if( a.xx < 0 ) {
  74.         return  -( (-a.xx) >> FP_FRCBITS ) ;
  75.     }
  76.     else {
  77.         return  a.xx >> FP_FRCBITS ;
  78.     }
  79. }
  80.  
  81.  
  82. /*------------------------------------------------------------------
  83.  fpnum to string / string to fp
  84. ------------------------------------------------------------------*/
  85. char *fptoa( const fpnum& n, char *s )
  86. {
  87. /*--
  88. Separate the integer and fractional parts.  This part is complicated
  89. because it must handle FP_MIN and FP_MAX.  Work with a positive
  90. fraction to make the bit shifting stuff work properly.
  91. --*/
  92.     long whole = n.xx >> FP_FRCBITS ;
  93.     long frac  = n.xx & ~( FP_ALLBITS << FP_FRCBITS ) ;
  94.     if( n.xx < 0  &&  frac != 0 ) {
  95.     frac = -frac ;
  96.     whole++ ;
  97.     }
  98.  
  99. /*--
  100. Set-up for calculating the fractional part in base 10.
  101.     bit_value = 0.5 * 10 ^ FP_MAXDECPL
  102. Do this only the first time the function is called.
  103. --*/
  104.     static long first_bit_value ;   // initialized to 0 at startup
  105.     if( !first_bit_value ) {
  106.         first_bit_value = 5 ;
  107.         for( int ii=0; ii<FP_MAXDECPL-1; ii++ ) {
  108.             first_bit_value *= 10 ;
  109.         }
  110.     }
  111.  
  112. //-- Mask off bits one by one, and add in their contribution if
  113. //   bit is set
  114.     long bit_value = first_bit_value ;
  115.     long mask = 1L << ( FP_FRCBITS - 1 ) ;
  116.     long decimal_frac = 0 ;
  117.     while( bit_value && mask ) {
  118.     if( mask & frac ) {
  119.         decimal_frac += bit_value ;
  120.     }
  121.     mask >>= 1 ;
  122.     bit_value >>= 1 ;
  123.     }
  124.  
  125. //-- Now have whole part and fract part in base 10.  Compose string:
  126.     sprintf( s, "%ld.%0*ld", whole, FP_MAXDECPL, decimal_frac ) ;
  127. //-- can truncate string here
  128.     return s ;
  129. }
  130.  
  131. /*------------------------------------------------------------------
  132.  Convert string to fixed point number
  133. ------------------------------------------------------------------*/
  134. static long ten[] = { 0, 10L, 100L, 1000L, 10000L, 100000L,
  135.               1000000L, 10000000L, 100000000L, 1000000000L } ;
  136.  
  137. #define NN  ( ( FP_FRCBITS*301 ) / 1000 )       // 301 = log(2)
  138.     // maximum number of decimal digits to consider without overflow
  139.  
  140. fpnum atofp( char *str )
  141. {
  142.     char  buf[ 20 ] ;
  143.     int   ii            = 0 ;
  144.     int   negative_flag = 0 ;
  145.     int   hit_decpt     = 0 ;
  146.     int max_digits      = 2 * NN ;
  147.  
  148.     fpnum  val ;           // initializes return value to zero
  149.  
  150.     if( !str ) return val ;
  151.  
  152.     while( isspace( *str ) ) str++ ;    // get past the white space
  153.  
  154.     if( !isdigit( *str ) ) {            // check for + - . symbols
  155.         if( *str == '-' ) {
  156.             negative_flag = 1 ;
  157.         }
  158.         else if( *str == '+' ) {
  159.         }
  160.         else if( *str == '.' ) {
  161.             hit_decpt = 1 ;
  162.         }
  163.         else {                          // not a +, -, or .
  164.             return val ;
  165.         }
  166.         str++ ;
  167.     }
  168.  
  169.     if( hit_decpt ) {
  170.         goto DEC_PT ;                   // it works for me
  171.     }
  172.  
  173. //-- Convert integer portion
  174.  
  175.     while( isdigit(*str) ) {
  176.         buf[ ii++ ] = *str++ ;
  177.     }
  178.     buf[ ii ] = '\0' ;
  179.     val.xx = (long)( atoi( buf ) ) << FP_FRCBITS ;
  180.  
  181.     if( *str++ != '.' ) {           // ++ gets past decimal point
  182.         goto RETURN ;
  183.     }
  184.  
  185. //-- Convert decimal portion
  186. DEC_PT:     // now str points to 1st digit after decimal point
  187.  
  188.     if( !isdigit( *str ) ) {
  189.         goto RETURN ;
  190.     }
  191.  
  192.     ii=0 ;
  193.     while( isdigit(*str)  &&  ii < NN ) {
  194.         buf[ ii++ ] = *str++ ;
  195.     }
  196.     buf[ ii ] = '\0' ;
  197.     val.xx += (2 * atol(buf) * FP_ONE + ten[ii] ) / ten[ii] / 2 ;
  198.  
  199.     while( isdigit(*str)  &&  ii < max_digits ) {
  200.     buf[ ii++ ] = *str++ ;
  201.     }
  202.     buf[ ii ] = '\0' ;
  203.     val.xx += (2 * atol(buf+NN) * FP_ONE + ten[ii] ) / ten[ii] / 2 ;
  204.  
  205. RETURN:
  206.     if( negative_flag )  val.xx = -val.xx ;
  207.     return val ;
  208. }
  209. #undef NN
  210.  
  211.  
  212. /*------------------------------------------------------------------
  213.  stream methods
  214. ------------------------------------------------------------------*/
  215. ostream& operator<<( ostream& o, const fpnum& n )
  216. {
  217.     static char str[25] ;
  218.     fptoa( n, str ) ;
  219.     o << str ;
  220.     return o ;
  221. }
  222.  
  223. /*------------------------------------------------------------------
  224.  initialize static class constants
  225. ------------------------------------------------------------------*/
  226. #if 0
  227. // Borland, Zortech, and TopSpeed do not allow these constants to be
  228. // initialized with the private constructor, though they should.
  229. const fpnum::fp_max( FP_MAX ) ;     // maximum fpnum
  230. const fpnum::fp_min( FP_MIN ) ;     // minimum fpnum
  231. const fpnum::fp_res( 1L ) ;         // fpnum resolution
  232. #endif
  233.  
  234.